﻿using System;
using System.Drawing;
using System.Windows.Forms;

namespace geekcmd
{
	enum FileViewStyle
	{
		Breif,
		Detail
	}

	class FileView : Control
	{
		#region Feilds
		ScrollBar scrollBar;
		FileViewStyle viewStyle;
		SortOrder sortOrder;
		FileList fileList;
		int selectedIndex;
		#endregion

		#region Initialization
		protected override CreateParams CreateParams
		{
			get
			{
				CreateParams createParams = base.CreateParams;
				createParams.Style |= 0x800000;
				return createParams;
			}
		}

		void InitializeComponent()
		{
			scrollBar = new HScrollBar();
			scrollBar.Dock = DockStyle.Bottom;
			Controls.Add(scrollBar);
		}

		public FileView()
		{
			InitializeComponent();

			SetStyle(ControlStyles.AllPaintingInWmPaint |
				ControlStyles.OptimizedDoubleBuffer |
				ControlStyles.UserPaint |
				ControlStyles.ResizeRedraw, true);

			BackColor = Color.White;

			Font = SystemFonts.IconTitleFont;

			Path = "C:\\";
		}
		#endregion

		#region Events
		event EventHandler<EventArgs> PathChanged;
		event EventHandler<EventArgs> SelectionChanged;

		void OnPathChanged(EventArgs e)
		{
			if (PathChanged != null)
			{
				PathChanged(this, e);
			}
		}

		void OnSelectionChanged(EventArgs e)
		{
			if (SelectionChanged != null)
			{
				SelectionChanged(this, e);
			}
		}
		#endregion

		#region Async Spirit Walk
		delegate FileList SpiritWalkDelegate(string path, SortOrder sortOrder);

		static FileList SpiritWalk(string path, SortOrder sortOrder)
		{
			FileList fileList = FileList.Walk(path);
			if (fileList != null)
			{
				fileList.Sort(sortOrder);
			}
			return fileList;
		}

		void SpiritWalkCallback(IAsyncResult asyncResult)
		{
			SpiritWalkDelegate spiritWalk = (SpiritWalkDelegate)asyncResult.AsyncState;
			FileList fileList = spiritWalk.EndInvoke(asyncResult);

			if (fileList != null)
			{
				MethodInvoker update = delegate()
				{
					this.fileList = fileList;
					selectedIndex = 0;
					Invalidate();
					OnPathChanged(EventArgs.Empty);
				};

				if (this.InvokeRequired)
				{
					this.Invoke(update, fileList);
				}
				else
				{
					update();
				}
			}
		}
		#endregion

		#region Properties
		public FileViewStyle ViewStyle
		{
			get { return viewStyle; }
			set
			{
			}
		}

		public string Path
		{
			get { return fileList.Path; }
			set
			{
				SpiritWalkDelegate spiritWalk = SpiritWalk;
				spiritWalk.BeginInvoke(value, sortOrder, SpiritWalkCallback, spiritWalk);
			}
		}

		public int SelectedIndex
		{
			get { return selectedIndex; }
			set
			{
				if (value >= 0 && value < fileList.Entries.Count)
				{
					selectedIndex = value;
					Invalidate();
				}
			}
		}

		public FileInfo Selected
		{
			get { return fileList.Entries[selectedIndex]; }
		}
		#endregion

		#region Keyboard Handling
		protected override bool IsInputKey(Keys keyData)
		{
			if (keyData == Keys.Up ||
				keyData == Keys.Down ||
				keyData == Keys.Left ||
				keyData == Keys.Right)
			{
				return true;
			}
			return base.IsInputKey(keyData);
		}

		protected override void OnKeyDown(KeyEventArgs e)
		{
			if (e.KeyCode == Keys.Down)
			{
				++SelectedIndex;
				e.Handled = true;
			}
			else if (e.KeyCode == Keys.Up)
			{
				--SelectedIndex;
				e.Handled = true;
			}
			else if (e.KeyCode == Keys.Return)
			{
				if (Selected.Directory)
				{
					Path = System.IO.Path.Combine(Path, Selected.Name);
				}
				e.Handled = true;
			}

			if ((e.Modifiers & Keys.Control) != 0)
			{
				if (e.KeyCode >= Keys.F3 && e.KeyCode <= Keys.F7)
				{
					sortOrder = (SortOrder)((int)e.KeyCode - (int)Keys.F3);
					Path = Path;
				}
			}

			base.OnKeyDown(e);
		}
		#endregion

		#region Focus
		protected override void OnGotFocus(EventArgs e)
		{
			base.OnGotFocus(e);
			Invalidate();
		}

		protected override void OnLostFocus(EventArgs e)
		{
			base.OnLostFocus(e);
			Invalidate();
		}
		#endregion

		#region Painting
		protected override void OnPaint(PaintEventArgs e)
		{
			System.Diagnostics.Trace.WriteLine(e.ClipRectangle.ToString());
			if (fileList != null)
			{
				Rectangle r = new Rectangle(1, 1, e.ClipRectangle.Width - 3, Font.Height);
				for (int i = 0; i < fileList.Entries.Count; ++i)
				{
					if (i == selectedIndex && Focused)
					{
						e.Graphics.DrawRectangle(Pens.Blue, r);
					}
					
					e.Graphics.DrawString(fileList.Entries[i].Name, Font, fileList.Entries[i].Directory ? Brushes.Blue : SystemBrushes.WindowText, r);
					r.Y += Font.Height;

					if (r.Y > e.ClipRectangle.Height)
					{
						break;
					}
				}
			}
			base.OnPaint(e);
		}
		#endregion
	}
}
